﻿package fpc.layouts;
import flash.display.Graphics;
import fpc.layouts.utility.LayoutAlgoritms;
import fpc.layouts.utility.SizeInfo;
import fpc.utils.Maths;
import fpc.layouts.ExcessSpaceMode;

class VLayout extends ALineLayout
{
	public function new() 
	{	
		super();
		_excessSpaceMode = UNIFORM;
	}
	
	public override function arrange()
	{
		universalArrange(false);
	}
	
	inline function universalArrange(horizontal:Bool)
	{
		var gap = horizontal ? _gapX : _gapY;
		var gapSize = {
			var num = _components.length;
			num > 1 ? (num - 1) * gap : 0;
		}
		
		if (_autoSize)
		{
			_sizeA = gapSize + .1;
			_sizeB = 0.;
		}
		else
		{
			_sizeA = horizontal ? width : height;
			_sizeB = horizontal ? height : width;
			if (_sizeA < gapSize + .1)
			{
				_sizeA = gapSize + .1;
			}
		}
		
		for (component in _components)
		{
			disableComponent(component);
		}
		
		// "WidthForHeight" isn't supported, only "HeightForWidth", like Qt. Or it's mistake and Qt has "WidthForHeight"?
		if (horizontal)
		{
			calculateA(horizontal, gap, gapSize);
			calculateB(horizontal);
		}
		else
		{
			calculateB(horizontal);
			calculateA(horizontal, gap, gapSize);
		}
		
		for (component in _components)
		{
			if (horizontal)
			{
				component.y = (_sizeB - component.height) * component.alignY;
			}
			else
			{
				component.x = (_sizeB - component.width) * component.alignX;
			}
			
			enableComponent(component);
		}
		
		width = horizontal ? _sizeA : _sizeB;
		height = horizontal ? _sizeB : _sizeA;
	}
	
	var _sizeA:Float;
	
	var _sizeB:Float;
	
	inline function calculateB(horizontal:Bool)
	{
		for (component in _components)
		{
			if (Math.isNaN(horizontal ? component.heightPortion : component.widthPortion))
			{
				var size = horizontal ? component.height : component.width;
				if (size > _sizeB)
				{
					_sizeB = size;
				}
			}
		}
		
		var needResizeB = false;
		for (component in _components)
		{
			var portion = horizontal ? component.heightPortion : component.widthPortion;
			if (!Math.isNaN(portion))
			{
				if (horizontal)
				{
					component.height = _sizeB * portion;
				}
				else
				{
					component.width = _sizeB * portion;
				}
				var size = horizontal ? component.height : component.width;
				if (size > _sizeB)
				{
					_sizeB = size;
					needResizeB = true;
				}
			}
		}
		
		if (needResizeB)
		{
			for (component in _components)
			{
				var portion = horizontal ? component.heightPortion : component.widthPortion;
				if (!Math.isNaN(portion))
				{
					if (horizontal)
					{
						component.height = _sizeB * portion;
					}
					else
					{
						component.width = _sizeB * portion;
					}
				}
			}
		}
	}
	
	inline function calculateA(horizontal:Bool, gap:Float, gapSize:Float)
	{
		var infos = [];
		var sumPortion = 0.;
		var sumScaled = Math.max(_sizeA - gapSize, 0);
		var num = _components.length;
		for (i in 0 ... num)
		{
			var component = _components[i];
			var portion = horizontal ? component.widthPortion : component.heightPortion;
			if (!Math.isNaN(portion))
			{
				sumPortion += portion;
				
				var info = SizeInfo.get();
				info.portion = portion;
				info.index = i;
				if (horizontal)
				{
					component.width = _sizeA;
					info.max = component.width;
					component.width = 0;
					info.min = component.width;
				}
				else
				{
					component.height = _sizeA;
					info.max = component.height;
					component.height = 0;
					info.min = component.height;
				}
				infos.push(info);
			}
			else
			{
				sumScaled -= horizontal ? component.width : component.height;
			}
		}
		
		var space = LayoutAlgoritms.distributeProportionally(sumScaled, sumPortion, infos);
		
		for (info in infos)
		{
			var component = _components[info.index];
			if (horizontal)
			{
				component.width = info.size;
			}
			else
			{
				component.height = info.size;
			}
			info.dispose();
		}
		
		var isUniform = false;
		var isCompact = false;
		var globalAlign = 0.;
		switch (_excessSpaceMode)
		{
			case UNIFORM:
				isUniform = true;
			case INCREASE_GAPS:
				isCompact = true;
				if (num > 1)
				{
					gap = gap + space / (num - 1);//TODO проверить случай с одним компонентом и без компонентов
				}
			case COMPACT_CONTAINER:
				isCompact = true;
			case MOVE_TO_EDGES(align):
				globalAlign = align;
		}
		if (isUniform && space > .1)
		{
			var offset = 0.;
			var spaceI = space / num;
			for (component in _components)
			{
				var size;
				if (horizontal)
				{
					component.x = offset + spaceI * component.alignX;
					size = component.width;
				}
				else
				{
					component.y = offset + spaceI * component.alignY;
					size = component.height;
				}
				offset += size + gap + spaceI;
			}
			_sizeA = offset - gap;
		}
		else
		{
			var offset = space * globalAlign;
			for (component in _components)
			{
				var size;
				if (horizontal)
				{
					component.x = offset;
					size = component.width;
				}
				else
				{
					component.y = offset;
					size = component.height;
				}
				offset += size + gap;
			}
			_sizeA = isCompact
				? offset - gap
				: offset - gap + space * (1 - globalAlign);
		}
	}
	
	public var excessSpaceMode(getExcessSpaceMode, setExcessSpaceMode):ExcessSpaceMode;
	var _excessSpaceMode:ExcessSpaceMode;
	function getExcessSpaceMode()
	{
		return _excessSpaceMode;
	}
	function setExcessSpaceMode(value)
	{
		_excessSpaceMode = value;
		heraldChange.dispatch(this);
		return value;
	}
}